package se.lnu.axez;

/*
 * Radius - 1, center - O
 */
public final class BoundingSphere implements IBoundingShape {
	private static final BoundingSphere SINGLETON = new BoundingSphere();
	
	public static BoundingSphere newInstance() {
		return SINGLETON;
	}
	
	private BoundingSphere() {}
	
	/*
	 * Implementation is based on http://paulbourke.net/geometry/sphereline/
	 */
	public float getIntersectionDistance(float[] pickRayCoordinates, int offset) {
		// we always consider sphere is in point O
		float x1 = pickRayCoordinates[offset + 0];
		float y1 = pickRayCoordinates[offset + 1];
		float z1 = pickRayCoordinates[offset + 2];
		float x2 = pickRayCoordinates[offset + 4];
		float y2 = pickRayCoordinates[offset + 5];
		float z2 = pickRayCoordinates[offset + 6];
		
		float xD = x2 - x1;
		float yD = y2 - y1;
		float zD = z2 - z1;
		
		float a = xD*xD + yD*yD + zD*zD;
		float b = 2f*(xD*x1 + yD*y1 + zD*z1);
		float c = x1*x1 + y1*y1 + z1*z1 - 1f;
		
		float d = b*b - 4f*a*c;
		if (d < 0f) {
			return NO_INTERSECTION;
		}
		
		float sqrt = (float) Math.sqrt(d);
		float t1 = (sqrt - b) / (2f*a);
		float t2 = (-sqrt - b) / (2f*a);
		float ti = Math.min(t1, t2);
		
		// calculate distance from ray near point to intersection point
		float xdi = x2*ti;
		float ydi = y2*ti;
		float zdi = z2*ti;
		
		return (float) Math.sqrt((xdi*xdi) + (ydi*ydi) + (zdi*zdi));
	}
}
